/****************************************************************************
**
**	File Name   : stdafx.cpp
**
**	Project     : DatChecker
**
**	Last Updated: $Header: /DatChecker.root/DatChecker/stdafx.cpp 5     1/20/04 12:08p Neusel $
**
**	Description : 
**
**		Declares all global variables and the _tWinMain() entry point.
**
****************************************************************************/
#include "stdafx.h"
#include "CmdLine.h"
#include "MainDlg.h"
#include "XMLProfile.h"
/*	----------------------------------------------------------------------
	Global Declarations
	----------------------------------------------------------------------	*/
CAppModule				_Module;
Options					theOptions;
CXMLProfile				theProfile(kStrAppTitle);
/*	----------------------------------------------------------------------
	Local Declarations
	----------------------------------------------------------------------	*/
static const LPCTSTR	kRootTag = _T("DATCHECKER");
static const LPCTSTR	kSection = _T("Options");

#define	IS_FLAG(p)		(*(p) == '-' || *(p) == '/')

static void				loadOptions(void);
static bool				parseCmdLine(LPTSTR);
static void				saveOptions(void);
/****************************************************************************
**
**	_tWinMain() --	
**
*/
int WINAPI 
_tWinMain(
	HINSTANCE	hInstance, 
	HINSTANCE	, 
	LPTSTR		lpstrCmdLine, 
	int			nCmdShow)
{
HRESULT	hr;
int		nRC = 0;

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);	// debug-only

hr = ::CoInitialize(NULL);
ATLASSERT(SUCCEEDED(hr));

::DefWindowProc(NULL, 0, 0, 0L);	// resolve ATL window thunking problem
	
AtlInitCommonControls(ICC_BAR_CLASSES);
hr = _Module.Init(NULL, hInstance);
if (SUCCEEDED(hr))
	{
	CMessageLoop	looper;
	CMainDlg		dlgMain;

	(void) _Module.AddMessageLoop(&looper);

	if (AtlIsOldWindows())
		(void) AtlMessageBox(NULL, IDS_OLD_WINDOWS);

	loadOptions();
	if (parseCmdLine(lpstrCmdLine) && dlgMain.Create(NULL))
		{
		dlgMain.ShowWindow(nCmdShow);
		nRC = looper.Run();
		saveOptions();
		}

	_Module.RemoveMessageLoop();
	}

_Module.Term();
::CoUninitialize();

return nRC;
}	/* end of _tWinMain() */
/****************************************************************************
**
**	Panic() --	fatal error handler.  Called when all hope of recovery is 
**				gone, and the only thing left to do is bail out and die.
**
**	NOTES:
**		1.	THIS FUNCTION DOES NOT RETURN if the error code is non-zero.
**
*/
void					
Panic(
	DWORD		dwErr,			// error code
	LPCTSTR		pstrFile,		// ptr to source file (__FILE__)
	UINT		uLine)			// source line number (__LINE__)
{
if (dwErr == NO_ERROR)
	return;	// Don't panic if it isn't an error!

ATLTRACE(_T("%s(%u): ### PANIC 0x%08lX ###\n"), pstrFile, uLine, dwErr);
//
//	Go get a message string for this error.  We're casting the result from a
//	DWORD to an int, so this code  will break if the length of any single 
//	message is > INT_MAX.
//
const int	kStrMsgLen	= MAX_PATH * 2;

int			nLen;
LPCTSTR		pstrSlash;
TCHAR		szMsg[kStrMsgLen+1],
			szTmp[kStrMsgLen+1];
			
nLen = (int) ::FormatMessage(	FORMAT_MESSAGE_FROM_SYSTEM | 
								FORMAT_MESSAGE_FROM_HMODULE | 
								FORMAT_MESSAGE_IGNORE_INSERTS,
								GetModuleHandle(NULL), dwErr, 
								0, szTmp, kStrMsgLen, NULL);
//
//	Now put up the message text.  Messages might have trailing whitespace or
//	a CRLF at the end, so clean up the string first. 
//
if (nLen > 0)	// true if message text available
	{
	for (int ndx = nLen - 1; ndx >= 0 && szTmp[ndx] < ' '; --ndx)
		szTmp[ndx] = '\0';
	}
else
	{
	(void)_snprintf(szTmp, kStrMsgLen, 
					_T("Error 0x%08lX"), 
					LOWORD(dwErr));
	}

pstrSlash = strrchr(pstrFile, '\\');
if (GOOD_PTR(pstrSlash))
	pstrSlash++;
else
	pstrSlash = GOOD_PTR(pstrFile) ? pstrFile : kStrEmpty;
//
//	Put up a prompt and tell the user what happened.  In DEBUG builds, the
//	user can hit "Retry", but in RELEASE builds no choice is offered.
//
#ifdef	_DEBUG
const DWORD		kMBStyle = MB_RETRYCANCEL|MB_ICONSTOP;
#else
const DWORD		kMBStyle = MB_OK|MB_ICONSTOP;
#endif

(void)_snprintf(szMsg, kStrMsgLen, 
				_T("%s\nat line %u of %s"), 
				szTmp, uLine, pstrSlash);
if (IDRETRY != ::MessageBox(NULL, szMsg, _T("PANIC!"), kMBStyle))
	::ExitProcess(dwErr);

_CrtDbgBreak();	// goes away in RELEASE builds
}	/* end of Panic() */
/****************************************************************************
**
**	loadOptions() -- initializes the global options structure (theOptions).
**
*/
static void
loadOptions(void)
{
::ZeroMemory(&theOptions, sizeof(Options));

theOptions.bGridLines		= true;	// gridlines are ON by default
theOptions.bVerify			= true;	// verify is ON by default
theOptions.nLanguage		= 0x00;	// default to US English
theOptions.clrTransparent	= RGB(0xFF,0x00,0xFF);

theProfile.Load(kRootTag);

(void) theProfile.Get(	kSection, _T("ObjInfoPos"),		theOptions.rObjInfoDlg);
(void) theProfile.Get(	kSection, _T("ObjViewPos"),		theOptions.rObjViewDlg);
(void) theProfile.Get(	kSection, _T("WindowPos"),		theOptions.rMainDlg);
(void) theProfile.Get(	kSection, _T("ObjDataPath"),	theOptions.szObjDataPath, MAX_PATH, 
#if	_DEBUG
						_T("C:\\Projects\\DatChecker\\Sample Data"));
#else
						_T("C:\\Program Files\\Infogrames Interactive\\RollerCoaster Tycoon 2\\ObjData") );
#endif
}	/* end of loadOptions() */
/****************************************************************************
**
**	parseCmdLine() --	parses the command-line arguments to search for flags.
**
*/
static bool
parseCmdLine(
	LPTSTR		pstrArgs)
{
LPCTSTR		pstrArg;
CCmdLine	cmdLine(pstrArgs);

for (SIZE_T ndx = 0; ndx < cmdLine.GetCount(); ++ndx)
	{
	pstrArg = cmdLine.GetAt(ndx);
	if (NULL_PTR(pstrArg))
		break;
	//
	//	See if it's a flag...
	//
	if (IS_FLAG(pstrArg))
		{
		while (IS_FLAG(pstrArg))	// tolerate GNU-style --flags
			pstrArg++;
		//
		//	See of there's an argument to go with the flag
		//
		LPCTSTR	pstrVal = strrchr(pstrArg, ':');

		if (NULL_PTR(pstrVal))
			pstrVal = strrchr(pstrArg, '=');

		if (GOOD_PTR(pstrVal))
			pstrVal++;	// skip over the separator

		if (StrCmpPartial(pstrArg, _T("custom")) == CSTR_EQUAL)
			theOptions.bCustomOnly = true;
		else if (StrCmpPartial(pstrArg, _T("language")) == CSTR_EQUAL)
			{
			if (GOOD_PTR(pstrVal))
				{
				const int	nRadix = (StrCmpPartial(pstrVal, "0x") == CSTR_EQUAL) ? 16 : 10;
				
				theOptions.nLanguage = strtol(pstrVal, NULL, nRadix);
				ATLTRACE("parseCmdLine() => language set to 0x%02X\n", theOptions.nLanguage);
				}
			else
				theOptions.nLanguage = 0x00;	// US English
			}
		else if (StrCmpPartial(pstrArg, _T("nogrid")) == CSTR_EQUAL)
			theOptions.bGridLines = false;
		else if (StrCmpPartial(pstrArg, _T("noverify")) == CSTR_EQUAL)
			theOptions.bVerify = false;
		else if (StrCmpPartial(pstrArg, _T("transparent")) == CSTR_EQUAL)
			{
			if (GOOD_PTR(pstrVal))
				{
				const int	nRadix = (StrCmpPartial(pstrVal, "0x") == CSTR_EQUAL) ? 16 : 10;
				
				theOptions.clrTransparent = strtol(pstrVal, NULL, nRadix);
				ATLTRACE("parseCmdLine() => transparent color set to 0x%08X\n", theOptions.clrTransparent);
				}
			else
				theOptions.clrTransparent = ::GetSysColor(COLOR_3DFACE);
			}
		}
	}
	
return true;
}	/* end of parseCmdLine() */
/****************************************************************************
**
**	saveOptions() -- stores the global options structure (theOptions).
**
*/
static void
saveOptions(void)
{
(void) theProfile.Put(	kSection, _T("ObjInfoPos"),		theOptions.rObjInfoDlg);
(void) theProfile.Put(	kSection, _T("ObjViewPos"),		theOptions.rObjViewDlg);
(void) theProfile.Put(	kSection, _T("WindowPos"),		theOptions.rMainDlg);
(void) theProfile.Put(	kSection, _T("ObjDataPath"),	theOptions.szObjDataPath); 

theProfile.Save();
}	/* end of saveOptions() */
/****************************************************************************
**
**	$History: stdafx.cpp $
 * 
 * *****************  Version 5  *****************
 * User: Neusel       Date: 1/20/04    Time: 12:08p
 * Updated in $/DatChecker.root/DatChecker
 * v1.7 -- rearranged Properties dialog and added yellow flags.
 * 
 * *****************  Version 4  *****************
 * User: Neusel       Date: 1/20/04    Time: 10:45a
 * Updated in $/DatChecker.root/DatChecker
 * v1.7 -- added AtlIsOldWindows() check.
 * 
 * *****************  Version 3  *****************
 * User: Neusel       Date: 1/15/04    Time: 12:45p
 * Updated in $/DatChecker.root/DatChecker
 * v1.6 -- improved command line parsing, better graphics scaling, add
 * "Copy to Clipboard" button.
 * 
 * *****************  Version 2  *****************
 * User: Neusel       Date: 10/27/03   Time: 11:43a
 * Updated in $/DatChecker.root/DatChecker
 * v1.3 -- added "/verify" flag to make object data check optional.
 * 
 * *****************  Version 1  *****************
 * User: Neusel       Date: 8/14/03    Time: 9:25a
 * Created in $/DatChecker.root/DatChecker
**
**	-------------------------------------------------------------------------
**
**	End of stdafx.cpp
**
****************************************************************************/
